package me.edzh.spring.bootstrap.interceptor;


import me.edzh.spring.bootstrap.annotations.NeedAuth;
import me.edzh.spring.bootstrap.controller.BaseController;
import me.edzh.spring.bootstrap.model.IUser;
import me.edzh.spring.bootstrap.model.Response;
import me.edzh.spring.bootstrap.utils.Constants;
import me.edzh.spring.bootstrap.utils.ResultCode;
import me.edzh.spring.bootstrap.utils.security.Jwt;
import org.apache.log4j.Logger;
import org.apache.log4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * Created by Edward on 2016/8/10.
 */
public class AuthInterceptor extends HandlerInterceptorAdapter {
    private final Logger logger = Logger.getLogger(AuthInterceptor.class);

    @Autowired(required = false)
    private PrivilegesChecker userDeterminedPrivilegesChecker;

    @Autowired(required = false)
    private ExternalAuthLogic externalAuthLogic;

    @Autowired
    private Jwt jwt;

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        String token = request.getHeader("Authorization");

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();

        NeedAuth annotation = method.getAnnotation(NeedAuth.class);
        IUser user = jwt.getUser(token);

        if (annotation != null) {
            if (user == null) {
                Response<?> dto = new Response<>();
                dto.setCode(ResultCode.ERROR_TOKEN_INVALID_CODE);
                dto.setMessage("token 不合法");
                BaseController.writeToClient(response, dto);
                return false;
            } else if (shouldBlockWithExternalCheck(token, user)) {
                Response<?> dto = new Response<>();
                dto.setCode(ResultCode.ERROR_EXTERNAL_CHECK_FAILED_CODE);
                dto.setMessage("token 不合法");
                BaseController.writeToClient(response, dto);
                return false;
            } else if (shouldBlockInCharacterCheck(user, annotation)) {
                Response<?> dto = new Response<>();
                dto.setCode(ResultCode.ERROR_TOKEN_WRONG_CHARACTER_CODE);
                dto.setMessage("token 不合法");
                BaseController.writeToClient(response, dto);
                return false;
            }
        }

        if (user != null && !shouldBlockWithExternalCheck(token, user)) {
            request.setAttribute(Constants.KEY_REQUEST_USER_ID, user.getId());
            MDC.put(Constants.LOG_USER_ID, user.getId());
        }

        return true;
    }

    private boolean shouldBlockWithExternalCheck(String token, IUser user) {
        if (externalAuthLogic != null) {
            return !externalAuthLogic.shouldPass(token, user);
        }

        return false;
    }

    /**
     * @return false - 通过, true - 不通过
     */
    private boolean shouldBlockInCharacterCheck(IUser user, NeedAuth annotation) {
        if (userDeterminedPrivilegesChecker == null) {
            return user.getAuthPrivileges() < annotation.value();
        }

        return userDeterminedPrivilegesChecker.shouldBlock(user, annotation.value());
    }


    public interface PrivilegesChecker {
        boolean shouldBlock(IUser user, int APIPrivileges);
    }

    public interface ExternalAuthLogic {
        boolean shouldPass(String token, IUser user);
    }
}
